//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	MetaSqlDatabase.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;

namespace Smart.Common
{
	/// <summary>
	/// Metadata for SQL Server Database
	/// </summary>
	[DebuggerDisplay("MetaSqlDatabase Name={Name} Title={Title}")]
	public class MetaSqlDatabase : MetaScope
	{
		/// <summary>
		/// Return guid for table name
		/// </summary>
		private static Guid GetDatabaseGuid(string name)
		{
			return new Guid((uint) StringComparer.OrdinalIgnoreCase.GetHashCode(name), 0xFC56, 0x4CDF, 0, 0, 0, 0, 0, 0, 0, 0);
		}

		/// <summary>
		/// Metadata for SQL Server Database
		/// </summary>
		public MetaSqlDatabase(string name)
			: base(GetDatabaseGuid(name), name, name)
		{
		}

		//public int GetSqlObjectId(object source, string name)
		//{
		//    var conn = (SqlConnection)source;
		//    using (var cmd = conn.CreateCommand())
		//    {
		//        cmd.CommandText = string.Format(SqlConst.AllObjectsIn, name);
		//        cmd.CommandTimeout = SqlConst.FastCommandTimeout;
		//        cmd.CommandType = CommandType.Text;

		//        using (var reader = cmd.ExecuteReader(CommandBehavior.SingleResult | CommandBehavior.SequentialAccess))
		//        {
		//            while (reader.Read())
		//            {
		//                return reader.GetInt32(0);
		//            }
		//        }
		//    }

		//    return 0;
		//}

		/// <summary>
		/// Fill cache info
		/// </summary>
		public override void LoadLists(object source, ICollection<string> includeLists, IDictionary<string, FacadeMappingInfo> mappingInfo)
		{
			var conn = (SqlConnection) source;
			var listMapping = new Dictionary<string, SqlFacadeMappingInfo>(StringComparer.OrdinalIgnoreCase);

			foreach (var info in mappingInfo.Values.Cast<SqlFacadeMappingInfo>())
				listMapping[info.ListName] = info;

			var sqlObjects = new List<MetaSqlObject>();

			using (var cmd = conn.CreateCommand())
			{
				cmd.CommandText = string.Format(SqlConst.AllObjectsIn, includeLists.Select(table => table.IncapsulateSql()).CastToString());
				cmd.CommandTimeout = SqlConst.FastCommandTimeout;
				cmd.CommandType = CommandType.Text;

				using (var reader = cmd.ExecuteReader(CommandBehavior.SingleResult | CommandBehavior.SequentialAccess))
				{
					while (reader.Read())
					{
						var oid = reader.GetInt32(0);
						var oname = reader.GetString(1).Trim();
						var otype = reader.GetString(2).Trim().ToUpper();

						if (otype.Out("P", "U", "V"))
							throw new NotSupportedException("ObjectType");

						var info = listMapping.SafeGet(oname);

						if (info == null)
							throw new ConfigurationErrorsException("scopeSettings");

						SqlObjectType ot;

						switch (otype)
						{
							case "P":
								ot = SqlObjectType.SP;
								break;

							case "V":
								ot = SqlObjectType.View;
								break;

							case "U":
								ot = SqlObjectType.Table;
								break;

							default:
								throw new NotSupportedException("ObjectType");
						}

						var ml = new MetaSqlObject(oid, oname, ot, info.PrimaryKey, info.TitleKey, this)
						         	{
						         		SPAdd = info.SPAdd,
						         		SPUpdate = info.SPUpdate,
						         		SPDelete = info.SPDelete,
						         		ResultCodeKey = info.ResultCodeKey,
						         		ResultDescriptionKey = info.ResultDescriptionKey
						         	};

						ListIDs[ml.ObjectId.ToString()] = ml.ID;
						ListIDs[ml.Name] = ml.ID;
						ListIDs[ml.ID.ToString("D")] = ml.ID;
						ListIDs[ml.ID.ToString("B")] = ml.ID;

						Lists[ml.ID] = ml;

						sqlObjects.Add(ml);
					}
				}
			}

			foreach (var sqlObject in sqlObjects)
			{
				sqlObject.LoadFields(conn);

				if (!sqlObject.SPAdd.IsNullOrEmpty())
					sqlObject.SPAddParameters = sqlObject.LoadParameters(conn, sqlObject.SPAdd);

				if (!sqlObject.SPUpdate.IsNullOrEmpty())
					sqlObject.SPUpdateParameters = sqlObject.LoadParameters(conn, sqlObject.SPUpdate);

				if (!sqlObject.SPDelete.IsNullOrEmpty())
					sqlObject.SPDeleteParameters = sqlObject.LoadParameters(conn, sqlObject.SPDelete);
			}
		}
	}
}